package legato.actions
{
	import flash.events.ContextMenuEvent;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.ui.ContextMenu;
	import flash.ui.ContextMenuItem;
	
	import mx.controls.Button;
	import mx.core.UIComponent;
	import mx.events.PropertyChangeEvent;
	
	/**
	 * Utility class for using actions with visual components. 
	 * @author Piotr
	 * 
	 */	
	public class ActionsUIBinder
	{
		
		private static var binersArray:Array = new Array();
		
		
		/**
		 * Saves binder in array not to loose reference to it and be garbage collected.
		 * Useful for ContextMenuItem binders. 
		 * @param binder
		 * 
		 */
		public static function registerBinder(binder:ActionsUIBinder):void
		{
			binersArray.push(binder);
		}
		
		
		/**
		 * Creates new ContextMenuItem bound to action. It's a shortcut method to create context menus as 
		 * ContextMenuItem is final class.  
		 * @param action action to bind
		 * @return created ContextMenuItem 
		 * 
		 */
		public static function createActionContextMenuItem(action:AbstractAction):ContextMenuItem
		{
			if (action == null)
			{
				throw new Error("Given action cannot be null");
			}
			var item:ContextMenuItem = new ContextMenuItem(action.label);
			var binder:ActionsUIBinder = new ActionsUIBinder();
			binder.bindToContextMenuItem(item,action);
			registerBinder(binder);
			return item;
		}
		
		
		/**
		 * Creates ContextMenu from array of actions. 
		 * @param actionsArray array od Actions
		 * @param hideBuiltInItems if true built in items are hidden
		 * @return created ContextMenu
		 * @see createActionContextMenuItem
		 */
		public static function createActionContextMenu(actionsArray:Array,hideBuiltInItems:Boolean = false):ContextMenu
		{
			var menu:ContextMenu = new ContextMenu();
			if (hideBuiltInItems)
			{
				menu.hideBuiltInItems();
			}
			for each (var action:AbstractAction in actionsArray)
			{
				menu.customItems.push(
					ActionsUIBinder.createActionContextMenuItem(action));	
			}
			return menu;
		}
				
		
		private var action:AbstractAction;
		
		private var uiComponent:UIComponent;
		
		private var menuItem:ContextMenuItem;
		
		/**
		 * Constructor 
		 * 
		 */
		public function ActionsUIBinder()
		{
		}
		
		/**
		 * Binds action to button. Button gets label, icon and tooltip from action and invokes it on mouse click. 
		 * @param uiComponent button component
		 * @param action action object
		 * 
		 */
		public function bindToButton(uiComponent:Button, action:AbstractAction):void
		{
			this.uiComponent = uiComponent;
			this.action = action;
			uiComponent.addEventListener(MouseEvent.CLICK,action.invoke);
			action.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,this.updateButton);
			this.updateButton(null);
		}
		
		/**
		 * Binds action to contect menu item. Menu item gets caption from action and invokes it on mouse click. 
		 * @param menuItem
		 * @param action action object
		 * 
		 */
		public function bindToContextMenuItem(menuItem:ContextMenuItem, action:AbstractAction):void
		{
			this.menuItem = menuItem; 
			this.action = action;
			menuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, action.invoke);
			action.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,this.updateContextMenuItem);
		}
		
		private function updateButton(event:Event):void
		{
			trace("update button ! "+this.action.label + "  "  + this.action.tooltipText);
			var button:Button = this.uiComponent as Button;
			if (button != null)
			{
				button.label = this.action.label != "" ? this.action.label : ("["+this.action.name+"]");	
				button.setStyle("icon",this.action.icon);
				button.toolTip = this.action.tooltipText;	
			}
		}
		
		private function updateContextMenuItem(event:Event):void
		{
			if (this.menuItem != null)
			{
				this.menuItem.caption = this.action.label != "" ? this.action.label : ("["+this.action.name+"]");
			}
			
		}
		
		

	}
}